/* 
 ********************************************************************
 * Project:     ethernet driver for LPC23xx/24xx
 * File:    	ethernet_lpc23xx.c
 *
 * System:   	ARM7TDMI-S 32 Bit
 * Compiler:  	GCC 4.0.3
 *
 * Date:      	2006-08-31
 * Author:    	Wenz
 *
 * Rights:    	Hitex Development Tools GmbH
 *            	Greschbachstr. 12
 *            	D-76229 Karlsruhe
 ********************************************************************
 * Description:
 *	
 * ethernet driver for LPC23xx controller ethernet module.
 * The iplementation is tested on a MCB2300 board with 
 * LPC2378 Controller 
 * DP8348C external PHY
 * 
 ********************************************************************
 * History:
 *
 *  Revision 1.0    2006/09/27      We
 *     Initial revision 
 ********************************************************************
 * This software is provided by the author 'AS IS' without any 
 * warranties. Hitex Development Tools GmbH shall not be held 
 * liable for any direct, indirect or consequential damages with
 * respect to any claims arising from the content of such software.
 ********************************************************************/



#include "peripherals_lpc23xx.h"        /* LPC23xx definitions               */
#include "ethernet_lpc23xx.h"
#include "peripherals_config.h"


/* extern declarations */

/* global function prototypes */

bool		eEthInit(void);
uint32_t	ulReadFrame(uint8_t* aFrameBuffer);
bool		eEthSendFrame(uint32_t frameLength, uint8_t* aFrameBuffer);
void		vEthSetStationAddress( uint8_t*	pAddress);
linkstatus	eGetLinkStatus(uint32_t	aPHYDevice);
void    	vEthIntHandler(void);
void        vEthIntService(void) __attribute__((naked)) ;



/* Local variables */

static const uint32_t	PHYREADCOMMAND = 0x01;
static const uint32_t	PHYWRITECOMMAND = 0x02;

static const uint32_t	MII_COMMAND_TIMEOUT = 0x5000;
static const uint32_t	MII_AUTONEG_TIMEOUT = 0x50000;
static const uint32_t	MII_LINKSTAT_TIMEOUT = 0x50000;

static const uint32_t	PHY_RESET_TIMEOUT = 0x10000;


/*
 *********************************************************************
 *	data for the DMA engine; descriptors
 *  location in ethernet RAM
 *********************************************************************/

 static eth_data*	const pxEthernetData = (eth_data*)ETHDATA_STARTADDRESS;

	
/* data exchange to application or stack 
 * only the length, pointer to data, and status is stored 
 * the data is left inside receive DMA engine				*/

static fragment	uxRxFrame[NUMBER_REC_FRAGMENTS];

static uint32_t	readIndex;
static uint32_t	writeIndex;		


/* error counters	*/

static	uint32_t	ulRxOverrunErrorCounter;
static	uint32_t	ulRxError;
static	uint32_t	ulTxUnderrunErrorCounter;
static	uint32_t	ulTxError;




/* local function prototypes */

static void		prvInitAPI(void);
static void		prvInitDMAEngine(void);

static uint16_t prvConfigurePHY(uint32_t	aPHYDevice);
static uint16_t prvReadPhyRegister( uint32_t aPhyRegisterAdr );
static uint16_t prvWritePhyRegister( uint32_t aPhyRegisterAdr, uint16_t aRegisterValue );
static void		prvConfigureRxFilters(void);

static void		prvReceiveFragment(void);
static void     prvSetupInt(uint32_t aIntSource, uint32_t aIntServiceAdr, uint32_t aPriority ); 


				

/* macros incrementing the index taking wrap around mechannism into account */
 
#define incRxIndex(Index)	if( (++Index) == NUMBER_REC_FRAGMENTS )			\
								Index = 0x00
#define incTxIndex(Index)	if( (++Index) == NUMBER_TX_FRAGMENTS )			\
								Index = 0x00


/****************************************************************************
* Name:			prvInitAPI
*                  	
* Description:	initialize the data which  should 
*				be interfaced to upper layers.
*						
* Parameters:	none
*					
* Return value:	none
*
****************************************************************************
*/
static void prvInitAPI(void)
{
	int		i;

	readIndex	= 0x00;
	writeIndex	= 0x00;

	ulRxOverrunErrorCounter = 0x00;
	ulRxError = 0x00;
	ulTxUnderrunErrorCounter = 0x00;
	ulTxError = 0x00;

	for( i = 0x00; i < NUMBER_REC_FRAGMENTS; i++ )
	{
		uxRxFrame[i].Length = 0x00;
		uxRxFrame[i].pReceived = 0x00;
		uxRxFrame[i].status = 0x00;
	}
}

/****************************************************************************
* Name:			prvInitDMAEngine
*                  	
* Description:	initialize the DMA registers 
*				note: the data to transfer via Ethernet
*				is located in 16K SRAM connected to AHB 1
*				at address 0x7FE00000 	
*				
*						
* Parameters:	none
*					
* Return value:	none
*
****************************************************************************
*/
static void prvInitDMAEngine(void)
{
	uint32_t i;

	// initialize receive DMA
	for( i=0; i < NUMBER_REC_FRAGMENTS; i++ )
	{
		pxEthernetData->xRxDescr[i].packet	 = (uint8_t*)(&pxEthernetData->ucRxBuffer[i][0]);
		pxEthernetData->xRxDescr[i].control  = MAXLENGTH_REC_FRAGMENT;
		pxEthernetData->xRxDescr[i].control |= RX_CONTROL_INT;
		pxEthernetData->xRxStat[i].info = 0x00;
		pxEthernetData->xRxStat[i].hashCRC = 0x00;
	}

	// configure receive descriptor register
	ETH_RXDESC	= (volatile uint32_t)&pxEthernetData->xRxDescr[0];					// start of rec data descr. table
	ETH_RXSTAT	= (volatile uint32_t)&pxEthernetData->xRxStat[0];					// start of rec status info table
	ETH_RXDESCRNO = NUMBER_REC_FRAGMENTS -1;	// number of descriptors -1	

	ETH_RXCONSIX = 0x00;						// consumer index	

	// initialize transmit DMA
	for( i=0; i < NUMBER_TX_FRAGMENTS; i++ )
	{
		pxEthernetData->xTxDescr[i].packet	 = &pxEthernetData->ucTxBuffer[i][0];
		pxEthernetData->xTxDescr[i].control  = 0x00;
		pxEthernetData->xTxStat[i].status	 = 0x00;
	}

	// configure transmit descriptor register
	ETH_TXDESC = (volatile uint32_t)&pxEthernetData->xTxDescr[0];					// start of transmit data table 
	ETH_TXSTAT = (volatile uint32_t)&pxEthernetData->xTxStat[0];					// start of transmit status table
	ETH_TXDESCRNO = NUMBER_TX_FRAGMENTS -1;	// number of descriptors -1	

	ETH_TXPRODIX = 0x00;						// producer index
}

/****************************************************************************
* Name:			prvReadPhyRegister
*                  	
* Description:	read a given register from phy ethernet  	
*				
*						
* Parameters:	aPhyRegisterAdr
*					address of the PHY register which is concatenated 
*					of device + register offset 
*					
* Return value:	register value (32 Bits) or 0xFFFF if access fails
*
****************************************************************************
*/
static uint16_t prvReadPhyRegister( uint32_t aPhyRegisterAdr )
{
	uint32_t	aTimeout;
	uint32_t 	aMII_Indicator;
	uint16_t	aRegisterValue = 0xFFFF;
	
   	ETH_MIIADR = aPhyRegisterAdr;
   	ETH_MIICMD = PHYREADCOMMAND;

	/* Wait until operation completed */

   	for (aTimeout = 0; aTimeout < MII_COMMAND_TIMEOUT; aTimeout++)
   	{
   		aMII_Indicator = ETH_MIIIND;
   		
      	if((aMII_Indicator & (0x01 << MII_IND_BUSY)) == 0)
      	{
      		aRegisterValue = (uint16_t)ETH_MIIRDD; 
        	break;
        }
   	}
   	ETH_MIICMD = 0x00;
   	return (aRegisterValue);
}

/****************************************************************************
* Name:			prvWritePhyRegister
*                  	
* Description:	write valuie to a given register of ethernet-phy  	
*				
*						
* Parameters:	aPhyRegisterAdr
*					address of the PHY register which is concatenated 
*					of device + register offset 
*				aRegisterValue
*					data to write
*					
* Return value:	0x00 	--> ok
*				0xFFFF 	--> fail
*
****************************************************************************
*/
static uint16_t prvWritePhyRegister( uint32_t aPhyRegisterAdr, uint16_t aRegisterValue )
{
	uint32_t	aTimeout;
	uint32_t 	aMII_Indicator;
	uint16_t	ret = 0xFFFF;
	
   	ETH_MIIADR = aPhyRegisterAdr;
    ETH_MIIWTD = aRegisterValue;


	/* Wait until operation completed */

   	for (aTimeout = 0; aTimeout < MII_COMMAND_TIMEOUT; aTimeout++)
   	{
   		aMII_Indicator = ETH_MIIIND;
   		
      	if((aMII_Indicator & ( 0x01 << MII_IND_BUSY)) == 0)
      	{
      		ret = 0x00;
        	break;
        }
   	}
   	return (ret);
}

/****************************************************************************
* Name:			prvConfigurePHY
*                  	
* Description:	configures the PHY registers according to 	
*				settings in config.h  
*				
*						
* Parameters:	aPHYDevice
*					address of the phy device in ETH
*					
* Return value:	extended Status register of DP83848C PHY
*				indicates link status among others
*
****************************************************************************
*/

static uint16_t  prvConfigurePHY(uint32_t	aPHYDevice)
{
	uint32_t	phyAddress = aPHYDevice << 8;
	uint32_t 	phyId = 0x00;
	uint32_t	aTimeout;
	uint16_t	basicModeStatus, extendedStatus, basicModeControl;


   /* Put the DP83848C in reset mode */
   prvWritePhyRegister (phyAddress | PHY_BMCR, 0x8000);

   /* Wait for hardware reset to end. */
   for (aTimeout = 0; aTimeout < PHY_RESET_TIMEOUT; aTimeout++)
   {
      basicModeControl = prvReadPhyRegister (phyAddress | PHY_BMCR);
      if (!(basicModeControl & PHY_RESET))
	  {
         /* Reset complete */
         break;
      }
   }

	// first of all check for the ethernet phy device
	
	phyId = prvReadPhyRegister( phyAddress | PHY_IDR1 );
	phyId <<= 16;
	phyId |= prvReadPhyRegister( phyAddress | PHY_IDR2 );

	// actually supports only DP83848C Phyter 
	switch( phyId)
	{
	case DP83848C_ID:

		if( LOOPBACK)
			prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_FULLD_100M | PHY_LOOPBACK);

		else
		{
			switch( PHYSPEED )
			{
			case AUTONEGOTIATION:

				/* configure autonegotiation  */
				prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_AUTO_NEG | PHY_RESTART_AUTON);

				/* Wait to complete Auto_Negotiation. */
   				for (aTimeout = 0; aTimeout < MII_AUTONEG_TIMEOUT; aTimeout++)
				{
					basicModeStatus = prvReadPhyRegister (phyAddress | PHY_BMSR);
					if (basicModeStatus & PHY_AUTO_DONE)				// autonegotiation complete
						break;
				}
				break;
		
			case FDX_100:
				prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_FULLD_100M );
				break;

			case FDX_10:
				prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_FULLD_10M );
				break;

			case HDX_100:
				prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_HALFD_100M );
				break;

			case HDX_10:
				prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_HALFD_10M );
				break;

			default: 
				prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_AUTO_NEG | PHY_RESTART_AUTON);
				break;

			}
		}
		/* Check the link status. */
		for (aTimeout = 0; aTimeout < MII_LINKSTAT_TIMEOUT; aTimeout++)
		{
			extendedStatus = prvReadPhyRegister (phyAddress | PHY_STS);
			if (extendedStatus & PHY_EXST_LINK_ESTABLISHED)			// link status 
				break;
		}
 		break;
	default :
		break;
	}
	return( extendedStatus);
}
/****************************************************************************
* Name:			prvConfigureRxFilters
*                  	
* Description:	configure receive filtering  
*				
*						
* Parameters:	none
*					
* Return value:	none
*  
****************************************************************************
*/

static void prvConfigureRxFilters(void)
{
	if(ACCEPTUNICAST)
		ETH_RXFILTERCTL  = RFC_UCAST_EN;		/* Accept Unicast Frames Enable      */

	if(ACCEPTBROADCAST)
		ETH_RXFILTERCTL |= RFC_BCAST_EN;		/* Accept Broadcast Frames Enable    */

	if(ACCEPTMULTICAST)
		ETH_RXFILTERCTL |= RFC_MCAST_EN;		/* Accept Multicast frames Enable    */

	if(ACCEPTPERFECT)
		ETH_RXFILTERCTL |= RFC_PERFECT_EN;		/* Accept Perfect Match Enable       */
}

/****************************************************************************
* Name:			vSetStationAddress
*                  	
* Description:	set the MAC address  
*				
*						
* Parameters:	pointer to byte array containing 6 bytes station address
*					
* Return value:	none
*  
****************************************************************************
*/
void vEthSetStationAddress( uint8_t*	pAddress)
{
	ETH_SA0 = ( (uint32_t)pAddress[0] <<8) | (uint32_t)pAddress[1];
	ETH_SA1 = ( (uint32_t)pAddress[2] <<8) | (uint32_t)pAddress[3];
	ETH_SA2 = ( (uint32_t)pAddress[4] <<8) | (uint32_t)pAddress[5];
}

/****************************************************************************
* Name:			vEthInit
*                  	
* Description:	Initialize  
*				
*						
* Parameters:	none
*					
* Return value:	TRUE -->  driver successfully initialized, link established
*				FALSE --> driver not initialized.
*
****************************************************************************
*/
bool eEthInit(void)
{
	uint16_t	aPhyStatus = 0x00;
	uint8_t		aMACAddress[6];
	uint32_t	Timeout;

	/* initialize data to application (stack) */
	prvInitAPI();

   	/* Power Up the ethernet MAC controller. */
   	PCONP |= PCON_ENET;

   	/* Ethernet port is GPIO_1 P1.0 up to P1.17  			
   	   enable ethernet by switching to Pinfunction 2 = 01    */

#ifdef RMII_INTERFACE  	
    /* P1.6, ETHERNET-TX_CLK, has to be set for ethernet module to address a BUG in 
		the engineering 
		version, even if this pin is not used for RMII interface. This bug has been fixed,
		and this port pin can be used as GPIO pin in the future release.  
		Unfortunately, this MCB2300 board still has the old eng. version LPC23xx chip
		on it. */
    PINSEL2 = 0x50151105;	/* selects P1[0,1,4,8,9,10,14,15] */
    PINSEL3 = 0x00000005;	/* selects P1[17:16] */

#elif 
	PINSEL2 = 0x55555555;							/* selects P1[15:0] */
   	PINSEL3 = (PINSEL3 & ~0x0000000F) | 0x00000005;	/* selects P1[17:16] */
#endif

	/* Reset all MAC internal modules. */
	ETH_MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX |
               MAC1_SIM_RES | MAC1_SOFT_RES;

	/* reset all datapaths and the host registers */
	ETH_COMMAND = CR_REG_RES | CR_TX_RES | CR_RX_RES;
 
	/* A short delay after reset. */
	for (Timeout = 200; Timeout; Timeout--);


	// remove reset conditions
	ETH_MAC1	= 0x00;
	ETH_MIICFG  = 0x00;
	ETH_COMMAND = 0x00;


	// Initialize DMA Interface

	prvInitDMAEngine();


   	/* Set reduced MII interface */
#ifdef RMII_INTERFACE

   	ETH_COMMAND = CR_RMII;
	ETH_PHYSUPP = 0;

	/* Reset Reduced MII Logic. */
	ETH_PHYSUPP = SUPP_RES_RMII;
	/* wait until reset done */
	for (Timeout = 200; Timeout; Timeout--)
		;

#else
   	ETH_COMMAND &= ~CR_RMII;
	ETH_PHYSUPP = 0;

	/* reset the MII management */
	ETH_MIICFG = 0x8000;
	/* wait until reset done */
	for (Timeout = 200; Timeout; Timeout--)
		;
#endif


	/* pass frames which are too short, but with valid CRC */
	ETH_COMMAND |= CR_PASS_RUNT_FRM;		


	/* configure PHY	*/
	aPhyStatus = prvConfigurePHY(PHY_DEVICE_NO_1);

	
	/* configure MAC control registers						*/

	ETH_MAC1 = 0x00; // MAC1_PASS_ALL;
	ETH_MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
	ETH_MAXF = ETH_MAX_FLEN;
	ETH_CLRT = CLRT_RETRANSMAX | CLRT_COLLWINDOW;
	ETH_IPGR = IPGR_DEF;

	/* Configure MAC 2 register depends on PHY extended Status */
	if (aPhyStatus & PHY_EXST_FDX)
	{
		ETH_MAC2    |= MAC2_FDPX_ENA;		/* Full duplex is enabled. */
		ETH_COMMAND |= CR_FULL_DUP;
		ETH_IPGT     = IPGT_FULL_DUP;
	}
	else 
		ETH_IPGT = IPGT_HALF_DUP;			/* Half duplex interpacket gap */


	/* Configure speed */
	if (aPhyStatus & PHY_EXST_SPEED_10M)
		ETH_PHYSUPP = 0;					/* 10MBit mode. */
	else
		ETH_PHYSUPP = SUPP_SPEED_100;		/* 100 MBit supported */
   

	/*
	* configure station address
	*
	* normally the MAC address is not derived from config.h. It should be 
	* read out of a serial EEPROM, Flash configuration or something else  */ 

	aMACAddress[0] = 0xA5;
	aMACAddress[1] = 0x91;
	aMACAddress[2] = 0x89;
	aMACAddress[3] = 0x03;
	aMACAddress[4] = 0x04;
	aMACAddress[5] = 0x09;

	vEthSetStationAddress( aMACAddress);

	
	/* configure receive filters	*/

	prvConfigureRxFilters();


	ETH_INTENABLE = INT_RX_DONE | INT_TX_DONE;	/* Enable RXdone & TXdone interrupts. */
	ETH_INTCLEAR  = 0xFFFF;					/* Reset all interrupts */

	ETH_COMMAND  |= (CR_RX_EN | CR_TX_EN);	/* Enable rx and tx mode of MAC Ethernet core */
	ETH_MAC1     |= MAC1_REC_EN;

	/* enable VIC for Ethernet interrupt. */
	if( INT_PRIORITY > 15 )
	   return( FALSE );
	   
    prvSetupInt(INT_SOURCE_ETH, (uint32_t)vEthIntService, INT_PRIORITY); 
    prvEnableEthInterrupt();   
  
    return(TRUE);
}

/****************************************************************************
* Name:			ulReadFrame
*                  	
* Description:	read a received frame from driver 
*				note: it is in response to the caller that 
*				there is enough memory allocated for the given 
*				frame pointer.  
*				
*						
* Parameters:	pointer to a Buffer which has enough space for 
*				the received frame data. 
*					
* Return value:	length of received data in bytes
*				0x00: --> nothing available
*
****************************************************************************
*/
uint32_t	ulReadFrame(uint8_t* aFrameBuffer)
{
	uint32_t	i;
	uint32_t	recLength = 0x00;
	uint8_t*	pRec = 0x00;
	bool		frameReceived;

	/* no frame buffer, then return with 0x00 */
	if( aFrameBuffer == 0x00 )	
		return( 0x00 );

	/* check readIndex */
	if( readIndex > NUMBER_REC_FRAGMENTS )
	{
		/* reset readIndex */
		readIndex = 0x00;
		for( i=0; i < (NUMBER_REC_FRAGMENTS -1); i++ )
		{
			if( (uxRxFrame[i].Length == 0x00) && (uxRxFrame[i+1].Length != 0x00) )
			{
				/* the valid readIndex found  correction sunccessful */
				readIndex = i+1;
				break;
			}
		}
	}

	/* check if a complete frame has been received */
	frameReceived = FALSE;
	for( i=0; i <NUMBER_REC_FRAGMENTS; i++ )
	{
		if( uxRxFrame[readIndex+i].status & FRAMECOMPLETE)
			frameReceived = TRUE;
	}

	/* copy all fragments of one frame to framebuffer */
	if( frameReceived)
	{
		// disable INTs
		prvDisableEthInterrupt();

		while( !(uxRxFrame[readIndex].status & FRAMECOMPLETE) ) 
		{
		    if( recLength != 0x00 )
		    {  
			 recLength += uxRxFrame[readIndex].Length;
			 pRec = uxRxFrame[readIndex].pReceived;

			 for( i = 0x00; i < recLength; i++ )
				*aFrameBuffer++ = *pRec++;  

			 uxRxFrame[readIndex].Length = 0x00;
			 uxRxFrame[readIndex].pReceived = 0x00;
			 uxRxFrame[readIndex].status = 0x00;
            }
			incRxIndex(readIndex);
		}
		/* now copy the last fragment */
		recLength += uxRxFrame[readIndex].Length;
		pRec = uxRxFrame[readIndex].pReceived;

		for( i = 0x00; i < recLength; i++ )
			*aFrameBuffer++ = *pRec++;  

		uxRxFrame[readIndex].Length = 0x00;
		uxRxFrame[readIndex].pReceived = 0x00;
		uxRxFrame[readIndex].status = 0x00;

		incRxIndex(readIndex);

		prvEnableEthInterrupt();
	}
	return(	recLength );
}

/****************************************************************************
* Name:			vEthSendFrame
*                  	
* Description:	transmit a delivered frame to the DMA engine
*				write a complete frame to transmit descriptor of next 
*				produce Index. After that increment ProduceIndex (take 
*				wrap around into account) 
*						
* Parameters:	- frameLength
*					count of bytes to transmit
*				- aFrameBuffer
*					buffer containing frame data
*					
* Return value:	- TRUE
*					frame delivered to HW (DMA engine)
*				- FALSE
*					cannot send frame, HW busy
* 
****************************************************************************
*/
bool eEthSendFrame(uint32_t frameLength, uint8_t* aFrameBuffer)
{
	uint32_t	i;
	uint8_t*	pTransmitDescrData;

	uint32_t	currentTXConsumeIndex, currentTXProduceIndex, nextTXProduceIndex;


	if( (frameLength == 0x00) || (aFrameBuffer == 0x00) )
		return(FALSE);

	if( frameLength > MAXLENGTH_TX_FRAME)
		return(FALSE);

	/* DMA send frame status  */ 
	currentTXProduceIndex = ETH_TXPRODIX;
	currentTXConsumeIndex = ETH_TXCONSIX;

	/* check if a produce buffer available */
	nextTXProduceIndex = currentTXProduceIndex;
	incTxIndex(nextTXProduceIndex);

	if( nextTXProduceIndex != currentTXConsumeIndex)
	{
		/* transmit buffer to hardware (DMA engine) */
		pTransmitDescrData = (uint8_t*)pxEthernetData->ucTxBuffer[currentTXProduceIndex];

		for( i= 0x00; i < frameLength; i++)
			pTransmitDescrData[i] = aFrameBuffer[i];
		
		pxEthernetData->xTxDescr[currentTXProduceIndex].control = frameLength - 1;
		pxEthernetData->xTxDescr[currentTXProduceIndex].control |= TC_LAST_FLAG | TX_CONTROL_INT;	/* last flag */

		ETH_TXPRODIX = nextTXProduceIndex;
		return(TRUE);
	}
	else
	{
		// no transmit buffers available
		return(FALSE); 
	}
}

/****************************************************************************
* Name:			prvReceiveFragment
*                  	
* Description:	handle an RX Done Int
*
*				copy received fragment information to receive array
*				for API. note: do not copy the data !!!
*				store length, pointer and status
*						
* Parameters:	none
*					
* Return value:	none
****************************************************************************
*/
void prvReceiveFragment(void)
{
	uint32_t	currentRxConsumeIndex, currentRxProduceIndex;
	uint32_t	currentFrameInfo;

	currentRxProduceIndex = ETH_RXPRODIX;
	currentRxConsumeIndex = ETH_RXCONSIX;


	// receive fragment int done

	while( currentRxConsumeIndex != currentRxProduceIndex )
	{
		currentFrameInfo =pxEthernetData->xRxStat[currentRxConsumeIndex].info;

		if(! (currentFrameInfo & RS_INFO_LAST_FLAG) )
		{
			uxRxFrame[writeIndex].status = 0x00;
			// this is a fragment, frame not complete
		}
		else
		{
			if( currentFrameInfo & RS_INFO_ERR)
			{
				/* receive frame error, normally skip frame
				   currently there is a flag named range error
				   which is set if there are frames of specific
				   ethernet types. These frames are correct and should
				   be stored.
				*/    
				uxRxFrame[writeIndex].status = FRAMECOMPLETE | FRAMEERROR; 
			}
			else
			{
				uxRxFrame[writeIndex].status = FRAMECOMPLETE;		// indicates frame complete
			}
		}
		uxRxFrame[writeIndex].Length += ((currentFrameInfo & RS_INFO_SIZE) -1);
		uxRxFrame[writeIndex].pReceived = pxEthernetData->xRxDescr[currentRxConsumeIndex].packet;
		incRxIndex(writeIndex);

		incRxIndex(currentRxConsumeIndex);
	}

	if( currentRxConsumeIndex == 0x00)
		currentRxConsumeIndex = 2;            

	ETH_RXCONSIX = currentRxConsumeIndex;
}
/****************************************************************************
* Name:			eGetLinkStatus
*                  	
* Description:	delivers the actual link status indicated by the external PHY 	
*				
*						
* Parameters:	none
*					
* Return value:	LINK_OFF
*				LINK_ON
*				NOLINKSTATE
*
****************************************************************************
*/

linkstatus eGetLinkStatus(uint32_t	aPHYDevice)
{
	uint32_t	phyAddress = aPHYDevice << 8;
	uint32_t 	phyId = 0x00;
	uint16_t	extendedStatus;


	// first of all check for the ethernet phy device
	
	phyId = prvReadPhyRegister( phyAddress | PHY_IDR1 );
	phyId <<= 16;
	phyId |= prvReadPhyRegister( phyAddress | PHY_IDR2 );

	// actually supports only DP83848C Phyter 
	switch( phyId)
	{
	case DP83848C_ID:

		/* Check the link status. */
		extendedStatus = prvReadPhyRegister (phyAddress | PHY_STS);

		if (extendedStatus & PHY_EXST_LINK_ESTABLISHED)			// link status 
			return(LINK_ON) ;
		else
			return(LINK_OFF);
 	
	default :
		break;
	}
	return( NOLINKSTATE);
}
/****************************************************************************
* Name:			vEthernetIntHandler
*                  	
* Description:	interrupt of Ethernet moduel occured
*				this could be one of the following ints
*				- receive fragment done
*				- transmit fragment done
*						
* Parameters:	none
*					
* Return value:	none
****************************************************************************
*/
void vEthIntHandler(void)
{
	uint32_t	aInterruptStatus; 
	uint32_t	currentRxProduceIndex;

	/* read interrupt status to get Int source */
	aInterruptStatus = ETH_INSTSTAT;


	/* receive status interrupts	*/
	if( aInterruptStatus & INT_RX_DONE )
	{
		/* receive fragment int done	*/
		ETH_INTCLEAR = INT_RX_DONE;
		prvReceiveFragment();
	}
	if( aInterruptStatus & INT_RX_OVERRUN)
	{
		/* receive overrun error */
		ETH_INTCLEAR = INT_RX_OVERRUN;
		ulRxOverrunErrorCounter++;
	}
	if( aInterruptStatus & INT_RX_ERR)
	{
		/* other receive errors, detailed in receive status */
		ETH_INTCLEAR = INT_RX_ERR;
		ulRxError++;
	}
	if( aInterruptStatus & INT_RX_FIN)
	{
		/* if we got such an Int it indicates   *
		* that the system is designed too slow  *
		* serving the Ethernet ints.			*
		* now frames might be lost				*/
		if( ! (aInterruptStatus & INT_RX_DONE ))
		{
			/* this case normally should not occur				*/
			/* if it does anyway, skip already received frames */
			ETH_INTCLEAR = INT_RX_FIN;
			currentRxProduceIndex = ETH_RXPRODIX;
			ETH_RXCONSIX = currentRxProduceIndex;
		}
	}
	/* transmit status interrupts	*/

	if( aInterruptStatus & INT_TX_DONE)
	{
		/* transmit fragment done	*/
		ETH_INTCLEAR = INT_TX_DONE;
	}
	if( aInterruptStatus & INT_TX_UNDERRUN)
	{
		/* transmit underrun error */
		ETH_INTCLEAR = INT_TX_UNDERRUN;
		ulTxUnderrunErrorCounter++;
	}
	if( aInterruptStatus & INT_TX_ERR)
	{
		/* transmit error			*/
		ETH_INTCLEAR = INT_TX_ERR;
		ulTxError++;
	}
	if( aInterruptStatus & INT_TX_FIN)
	{
		/* do nothing */
		ETH_INTCLEAR = INT_TX_FIN;
	}

	/* acknowledge interrupt in VIC */
	prvIntAck();                    		// Acknowledge Interrupt
}
/****************************************************************************
* Name:			vEthIntService
*                  	
* Description:	interrupt service routine called directly
*				from vectored interrupt controller
*
*               this inline assembler saves registers, then calls 
*               the C-function Ethernet handler, restores
*               registers and exits IRQ.
*    
* Parameters:	none
*					
* Return value:	none
****************************************************************************
*/
void vEthIntService(void)
{}/*											
	asm volatile(	
	"SUB	lr,lr, #4				\n\t"		
    "STMFD  sp!,{r0-r12,lr}			\n\t"		
    "MRS    r1,spsr					\n\t"		
    "STMFD  sp!,{r1}				\n\t"	   
 	"BL 		vEthIntHandler		\n\t"		
    "LDMFD   sp!,{r1}				\n\t"	
    "MSR     spsr_cxsf,r1			\n\t"	
    "LDMFD   sp!,{r0-r12,pc}^		\n\t"	
	);										
}  */
/****************************************************************************
* Name:			prvSetupInt
*                  	
* Description:	inserts the interrupt service routine into the vectorŽ
*               table.
*
*    
* Parameters:	aIntSource
*                   source of the interrupt (Ethernet controller)
*               aInstServiceAdr
*                   address of the  interrupt service routine
*               aPriority
*                   priority of the interrupt.
*					
* Return value:	none
****************************************************************************
*/
static void prvSetupInt(uint32_t aIntSource, uint32_t aIntServiceAdr, uint32_t aPriority ) 
{
	uint32_t*  aVectorAdr = (uint32_t*)(&VICVectAddr0);	// this is the first table address
	uint32_t*  aPriorityAdr = (uint32_t*)(&VICVectPriority0);	
  
    *(aVectorAdr + aIntSource) = aIntServiceAdr;     		// set interrupt vector
    *(aPriorityAdr + aIntSource) = aPriority;     			// set priority
}


/*----------------------------------------------------------------------------
 * end of file
 *---------------------------------------------------------------------------*/

